package com.dcy.system.biz.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dcy.common.constant.RedisConstant;
import com.dcy.common.exception.BusinessException;
import com.dcy.common.model.PageModel;
import com.dcy.common.model.PageResult;
import com.dcy.db.base.service.DcyBaseService;
import com.dcy.system.api.api.UserApi;
import com.dcy.system.api.dto.out.UserInfoListOutDTO;
import com.dcy.system.biz.convert.RoleConvert;
import com.dcy.system.biz.convert.UserInfoConvert;
import com.dcy.system.biz.dao.RoleDao;
import com.dcy.system.biz.dao.UserInfoDao;
import com.dcy.system.biz.dao.UserPostDao;
import com.dcy.system.biz.dao.UserRoleDao;
import com.dcy.system.biz.enums.SystemApiErrorCode;
import com.dcy.system.biz.model.UserInfo;
import com.dcy.system.biz.model.UserPost;
import com.dcy.system.biz.model.UserRole;
import com.dcy.system.biz.vo.in.*;
import com.dcy.system.biz.vo.out.RoleListOutVO;
import com.dcy.system.biz.vo.out.UserInfoListExcelOutVO;
import com.dcy.system.biz.vo.out.UserInfoListOutVO;
import com.dcy.system.biz.vo.out.UserInfoRoleOutVO;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author dcy
 * @since 2020-08-19
 */
@RequiredArgsConstructor
@DubboService(interfaceClass = UserApi.class)
public class UserInfoService extends DcyBaseService implements UserApi {

    private static final BCryptPasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();

    private final UserInfoDao userInfoDao;
    private final UserPostDao userPostDao;
    private final UserRoleDao usrRoleDao;
    private final RoleDao roleDao;
    private final UserInfoConvert userInfoConvert = UserInfoConvert.INSTANCE;
    private final RoleConvert roleConvert = RoleConvert.INSTANCE;

    /**
     * 根据用户名获取用户信息
     *
     * @param username
     * @return
     */
    @Override
    public UserInfoListOutDTO getUserInfoByUsername(String username) {
        return userInfoConvert.toOutDto(userInfoDao.getUserInfoByUsername(username));
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param username
     * @return
     */
    public UserInfoListOutVO getUserInfo(String username) {
        return userInfoConvert.toOut(userInfoDao.getUserInfoByUsername(username));
    }

    /**
     * 根据用户id 查询已授权角色列表
     *
     * @param userId
     * @return
     */
    public List<RoleListOutVO> getAuthRoleList(String userId) {
        return roleConvert.toOutList(roleDao.selectRoleListByUserId(userId));
    }

    /**
     * 保存授权角色
     *
     * @param userInfoRoleOutVO
     * @return
     */
    @CacheEvict(value = {RedisConstant.USER_ROLE}, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveAuthRole(UserInfoRoleOutVO userInfoRoleOutVO) {
        boolean success = false;
        if (StrUtil.isNotBlank(userInfoRoleOutVO.getUserId()) && userInfoRoleOutVO.getRoleIds() != null) {
            // 删除关联表
            usrRoleDao.remove(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getUserId, userInfoRoleOutVO.getUserId()));
            // 添加关联表
            usrRoleDao.saveBatch(userInfoRoleOutVO.getRoleIds().stream().map(roleId -> new UserRole().setUserId(userInfoRoleOutVO.getUserId()).setRoleId(roleId)).collect(Collectors.toList()));
            success = true;
        }
        return success;
    }

    /**
     * 自定义sql分页查询
     *
     * @param userInfoSearchInVO
     * @param pageModel
     * @return
     */
    public PageResult<UserInfoListOutVO> pageUserList(UserInfoSearchInVO userInfoSearchInVO, PageModel pageModel) {
        return toPageResult(userInfoDao.pageListByEntity(userInfoConvert.toUserInfo(userInfoSearchInVO), pageModel), page -> userInfoConvert.toOutList(page.getRecords()));
    }

    /**
     * 保存用户和岗位
     *
     * @param userInfoCreateInVO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean save(UserInfoCreateInVO userInfoCreateInVO) {
        boolean success = false;
        UserInfo userInfo = userInfoConvert.toUserInfo(userInfoCreateInVO);
        userInfo.setPassword(PASSWORD_ENCODER.encode(userInfoCreateInVO.getPassword()));
        if (userInfoDao.save(userInfo)) {
            userPostDao.remove(Wrappers.<UserPost>lambdaQuery().eq(UserPost::getUserId, userInfo.getId()));
            userPostDao.saveBatch(userInfoCreateInVO.getPostIds().stream().map(postId -> new UserPost().setUserId(userInfo.getId()).setPostId(postId)).collect(Collectors.toList()));
            success = true;
        }
        return success;
    }

    /**
     * 修改用户和岗位
     *
     * @param userInfoUpdateInVO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean update(UserInfoUpdateInVO userInfoUpdateInVO) {
        boolean success = false;
        UserInfo userInfo = userInfoConvert.toUserInfo(userInfoUpdateInVO);
        if (userInfoDao.updateById(userInfo)) {
            userPostDao.remove(Wrappers.<UserPost>lambdaQuery().eq(UserPost::getUserId, userInfo.getId()));
            userPostDao.saveBatch(userInfoUpdateInVO.getPostIds().stream().map(postId -> new UserPost().setUserId(userInfo.getId()).setPostId(postId)).collect(Collectors.toList()));
            success = true;
        }
        return success;
    }

    /**
     * 删除
     *
     * @param id
     * @return
     */
    public Boolean delete(String id) {
        return userInfoDao.removeById(id);
    }

    /**
     * 批量删除
     *
     * @param idList
     * @return
     */
    public Boolean deleteBatch(List<String> idList) {
        return userInfoDao.removeBatchByIds(idList);
    }

    /**
     * 重置密码
     *
     * @param userInfoResetPassInVO
     * @return
     */
    public boolean resetPassword(UserInfoResetPassInVO userInfoResetPassInVO) {
        UserInfo userInfo = userInfoConvert.toUserInfo(userInfoResetPassInVO);
        userInfo.setPassword(PASSWORD_ENCODER.encode(userInfoResetPassInVO.getPassword()));
        return userInfoDao.updateById(userInfo);
    }

    /**
     * 修改基本信息
     *
     * @param userInfoUpdateInfoInVO
     * @return
     */
    public boolean updateInfo(UserInfoUpdateInfoInVO userInfoUpdateInfoInVO) {
        return userInfoDao.updateById(userInfoConvert.toUserInfo(userInfoUpdateInfoInVO));
    }

    /**
     * 修改密码
     *
     * @param userUpdatePassInVO
     * @return
     */
    public boolean updatePass(UserUpdatePassInVO userUpdatePassInVO) {
        UserInfo userInfo = userInfoDao.getById(userUpdatePassInVO.getUserId());
        if (!PASSWORD_ENCODER.matches(userUpdatePassInVO.getCurrentPass(), userInfo.getPassword())) {
            throw new BusinessException(SystemApiErrorCode.USER_UPDATE_PASS_ERROR);
        }
        if (!userUpdatePassInVO.getNewPass().equalsIgnoreCase(userUpdatePassInVO.getConfPass())) {
            throw new BusinessException(SystemApiErrorCode.USER_UPDATE_PASS2_ERROR);
        }
        UserInfo updatePassUser = new UserInfo();
        updatePassUser.setId(userUpdatePassInVO.getUserId());
        updatePassUser.setPassword(PASSWORD_ENCODER.encode(userUpdatePassInVO.getNewPass()));
        return userInfoDao.updateById(updatePassUser);
    }

    /**
     * 获取导出excel数据
     *
     * @return
     */
    public List<UserInfoListExcelOutVO> getExcelList() {
        return userInfoConvert.toExcelList(userInfoDao.list());
    }

    /**
     * 根据用户id 查询岗位id
     *
     * @param userId
     * @return
     */
    public List<String> getPostListByUserId(String userId) {
        return userPostDao.getPostIdListByUserId(userId);
    }
}
